using System;
using Spine;
using Spine.Unity;
using Spine.Unity.AttachmentTools;
using UnityEngine;

/// <summary>
/// 换皮测试
/// </summary>
public class SpineChangeSkin : MonoBehaviour
{
    private SkeletonGraphic skeletonAnimation;
    private SkeletonDataAsset skeletonDataAsset;
    private Material sourceMaterial;
    private SkeletonData skeletonData;

    private bool applyPma = true;

    [SpineSkin] private string templateSkinName;//模板皮肤名称（初始）

    private Skin equipsSkin;
    private Skin collectedSkin;

    #region 优化皮肤用
    private Material runtimeMaterial;
    private Texture2D runtimeAtlas;
    #endregion

    #region ChangeShin需要的 外部可显示 选择
    //[SpineSlot] public string slot1; //骨骼槽点
    //[SpineSkin] public string templateSkin;

    //[SpineAttachment(skinField: "templateSkin")]
    //public string templateAttachment;
    #endregion

    void Start()
    {
        skeletonAnimation = GetComponent<SkeletonGraphic>();
        skeletonDataAsset = skeletonAnimation.SkeletonDataAsset;
        sourceMaterial = skeletonDataAsset.atlasAssets[0].PrimaryMaterial;
        skeletonData = skeletonAnimation.Skeleton.Data;




        ReSetSkin();
    }

    private void ReSetSkin()
    {
        var skeleton = skeletonAnimation.Skeleton;
        var skin = skeleton.Skin;
        if (skin == null)
            templateSkinName = "default";
        else
            templateSkinName = skin.Name;

        equipsSkin = new Skin("Equips");
        var tSkin = skeletonData.FindSkin(templateSkinName);

        if (tSkin != null)
            equipsSkin.AddAttachments(tSkin);

        skeletonAnimation.Skeleton.Skin = equipsSkin;
        RefreshSkeletonAttachments();
    }


    /// <summary>
    /// 局部换皮
    /// </summary>
    /// <param name="slot">骨骼槽点昵称</param>
    /// <param name="attachmentName">SpineAttachment 类型 一般和slot名称相同</param>
    /// <param name="sprite">要更改的贴图[需要开启读写功能]</param>
    public void ChangeShin(string slot, string attachmentName,Sprite sprite)
    {
        int slotIndex = skeletonData.FindSlot(slot).Index;//根据骨骼槽点 找到槽点索引
        Attachment attachment = GenerateAttachment(slotIndex, templateSkinName, attachmentName, sprite);
        if (attachment == null)return;

        equipsSkin.SetAttachment(slotIndex, attachmentName, attachment);
        skeletonAnimation.Skeleton.SetSkin(equipsSkin);
        RefreshSkeletonAttachments();
        OptimizeSkin();
    }

    private Attachment GenerateAttachment(int slotIndex, string tSkinName, string attachmentName,Sprite sprite)
    {
        var sData = skeletonDataAsset.GetSkeletonData(true);
        var tSkin = sData.FindSkin(tSkinName);
        Attachment tAttachment = tSkin.GetAttachment(slotIndex, attachmentName);
        if (tAttachment == null)
        {
            Debug.LogError($"skin {tSkinName} slotIndex {slotIndex} attachmentName {attachmentName} ==》attachment=null");
            return null;
        }
        var attachment = tAttachment?.GetRemappedClone(sprite, sourceMaterial, premultiplyAlpha: this.applyPma);
        return attachment;
    }

    /// <summary>
    /// 刷新皮肤
    /// </summary>
    void RefreshSkeletonAttachments()
    {
        skeletonAnimation.Skeleton.SetSlotsToSetupPose();
        skeletonAnimation.AnimationState.Apply(skeletonAnimation.Skeleton); //skeletonAnimation.Update(0);
    }

    /// <summary>
    /// 优化皮肤 将换过皮肤的贴图 整合到一张贴图中 [人物贴图需要开启读写功能]
    /// </summary>
    public void OptimizeSkin()
    {
        try
        {
            // 1. 收集所有活动皮肤的所有附件。
            collectedSkin = collectedSkin ?? new Skin("Collected skin");
            collectedSkin.Clear();
            collectedSkin.AddAttachments(skeletonAnimation.Skeleton.Data.DefaultSkin);
            collectedSkin.AddAttachments(equipsSkin);

            // 2. 创造一个重新包装的皮肤。
            // 注意:GetRepackedSkin()返回的材质和纹理行为类似于'new Texture2D()'，需要销毁
            if (runtimeMaterial)
                Destroy(runtimeMaterial);
            if (runtimeAtlas)
                Destroy(runtimeAtlas);
            var repackedSkin = collectedSkin.GetRepackedSkin("Repacked skin",sourceMaterial, out runtimeMaterial,out runtimeAtlas);
            collectedSkin.Clear();

            // 3.使用重新包装的皮肤。
            skeletonAnimation.Skeleton.Skin = repackedSkin;
            RefreshSkeletonAttachments();
        }
        catch (Exception e)
        {
            Debug.LogError($"OptimizeSkin 异常：{e.Message}");
        }
    }
}
